#include <ESP8266HTTPClient.h>
#include <Adafruit_AHT10.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <WakeOnLan.h>
#include <WiFiUDP.h>
#include <Arduino.h>
#include <U8g2lib.h>
#include <EEPROM.h>
#include <Ticker.h>
#include <Wire.h>

#include "main.h"
#include "PubSubClient.h" 

WiFiUDP Udp;
WakeOnLan WOL(Udp);
Adafruit_AHT10 aht;
WiFiClient espClient;
PubSubClient client(espClient);
HTTPClient http_bemfa_HTTPClient;
WiFiClient client_bemfa_WiFiClient;

#define SDA_PIN 0
#define SCL_PIN 2
#define MyTimer 3000

U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
//U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE, /* clock=*/ 0, /* data=*/ 2);
void loadConfig()
{
  uint8_t mac[6];
  Serial.println(" LoadConfig.......");
  WiFi.macAddress(mac);
  EEPROM.begin(512);
  for (int i = 0; i < sizeof(config); i++)
  {
    *(p + i) = EEPROM.read(i);
  }
  config.reboot = config.reboot + 1;
  if(config.reboot>=4){
    restoreFactory();
  }
  if(config.magic != 0xAA){
    config_flag = 1;
  }
  EEPROM.begin(512);
  for (int i = 0; i < sizeof(config); i++){
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
  delay(2000);
  Serial.println("loadConfig Over");
  EEPROM.begin(512);
  config.reboot = 0;
  for (int i = 0; i < sizeof(config); i++){
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
  delay(2000);
}

void restoreFactory()
{
  Serial.println("\r\n Restore Factory....... ");
  u8g2.setFont(u8g2_font_10x20_tf);
  u8g2.firstPage();
  do {
    u8g2.drawStr(29, 30, "Restore");
    u8g2.drawStr(29, 45, "Factory...");
  } while (u8g2.nextPage());

  config.magic = 0x00;
  strcpy(config.stassid, "");
  strcpy(config.stapsw, "");
  strcpy(config.cuid, "");
  strcpy(config.ctopic, "");
  config.magic = 0x00;
  saveConfig();
  delayRestart(1);
  while (1) {
    ESP.wdtFeed();
    delay(100);
  }
}

void saveConfig()
{
  config.reboot = 0;
  EEPROM.begin(2018);
  uint8_t *p = (uint8_t*)(&config);
  for (int i = 0; i < sizeof(config); i++)
  {
    EEPROM.write(i, *(p + i));
  }
  EEPROM.commit();
}
Ticker delayTimer;
void delayRestart(float t) {
  delayTimer.attach(t, []() {
    ESP.restart();
  });
}
void apConfig(String mac){
  if(config_flag == 1){
      WiFi.softAP("MyDevice"+mac);
      Udp.begin(8266);
      Serial.println("Started Ap Config...");
  }
  String topic = mac+aptype;
  while(config_flag){//如果未配网，开启AP配网，并接收配网信息
        int packetSize = Udp.parsePacket();

        u8g2.setFont(u8g2_font_10x20_tf);
        u8g2.firstPage();
        do {
          u8g2.drawStr(24, 25, "MyDevice");
          u8g2.drawStr(34, 55, mac.c_str());
        } while (u8g2.nextPage());
        
        if (packetSize) {
          Serial.print("Received packet of size ");
          Serial.println(packetSize);
          Serial.print("From ");
          IPAddress remoteIp = Udp.remoteIP();
          Serial.print(remoteIp);
          Serial.print(", port ");
          Serial.println(Udp.remotePort());

          int len = Udp.read(packetBuffer, 255);
          if (len > 0) {
            packetBuffer[len] = 0;
          }
          Serial.println("Contents:");
          Serial.println(packetBuffer);
          StaticJsonDocument<200> doc;
      
          DeserializationError error = deserializeJson(doc, packetBuffer);
          if (error) {
            Serial.print(F("deserializeJson() failed: "));
            Serial.println(error.f_str());
            return;
          }
          int cmdType = doc["cmdType"].as<int>();;
  
          if (cmdType == 1) {
              const char* ssid = doc["ssid"];
              const char* password = doc["password"];
              const char* token = doc["token"];
              Serial.println(cmdType);
              Serial.println(ssid);
              Serial.println(password);
              Serial.println(token);
              strcpy(config.stassid, ssid);
              strcpy(config.stapsw, password);
              strcpy(config.cuid, token);
              config.reboot = 0;
              config.magic = 0xAA;
              saveConfig();
              //收到信息，并回复
              String  ReplyBuffer = "{\"cmdType\":2,\"productId\":\""+topic+"\",\"deviceName\":\""+""+"\",\"protoVersion\":\""+verSion+"\"}";
              Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
              Udp.write(ReplyBuffer.c_str());
              Udp.endPacket();
            
          }else if(cmdType == 3){
              config_flag = 0;
              WiFi.softAPdisconnect(true);
          } 
        } 
  }
}

void getUid(String mac, bool reConfig) {
  if (strcmp(config.cuid, "") == 0 || reConfig) {

    http_bemfa_HTTPClient.begin(client_bemfa_WiFiClient, "http://api.bemfa.com/api/device/v1/airkiss/?topic=" + mac + "&version=" + verSion + "&ad=" + adminID);
    httpCode = http_bemfa_HTTPClient.GET();
    if (httpCode > 0) {
      String payload = http_bemfa_HTTPClient.getString();
      //json数据解析
      StaticJsonDocument<200> doc;
      DeserializationError error = deserializeJson(doc, payload);
      if (error) {
        Serial.print(F("deserializeJson() failed: "));
        Serial.println(error.c_str());
      }
      String code = doc["code"];
      if (code == "5723200") {
        String docUID = doc["uid"];
        strcpy(config.cuid, docUID.c_str());
        strcpy(config.ctopic, mac.c_str());
        saveConfig();
      } else {
        Serial.println(" config ERROR.........");
      }

      http_bemfa_HTTPClient.end();
    }
  }
  if (strcmp(config.ctopic, "") == 0) {
    TOPIC = mac;
  } else {
    TOPIC = config.ctopic;
  }
  UID = config.cuid;
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(UID.c_str())) {
      Serial.println("connected");

      client.subscribe(TOPIC.c_str());  //订阅
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String Mqtt_Buff = "";
  for (int i = 0; i < length; i++) {
    Mqtt_Buff += (char)payload[i];
  }
  Serial.print(Mqtt_Buff);
  Serial.println();
    if (Mqtt_Buff == "on") {
    turnOn();            
  } 
  else if (Mqtt_Buff == "off") {
    turnOff();                   
  }
  else {
    int index = Mqtt_Buff.indexOf("MAC=");
    if (index != -1) {
      String mac =  Mqtt_Buff.substring(index + 4);
      mac.toCharArray(buf,mac.length()+1);
      memcpy(config.MACAddress, buf, sizeof(buf));
      Serial.printf(buf);
      saveConfig();
    }
  }
  Mqtt_Buff = "";
}

void turnOn(){
  Serial.println("Turn ON");
  pcState = true;
  WOL.sendMagicPacket(config.MACAddress);
}

void turnOff(){
  Serial.println("Turn OFF");
  pcState = false;
}

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA_PIN, SCL_PIN);
  u8g2.begin();

  u8g2.setFont(u8g2_font_10x20_tf);
  u8g2.firstPage();
  do {
    u8g2.drawStr(44, 30, "wifi");
    u8g2.drawStr(29, 45, "connect...");
  } while (u8g2.nextPage());

  topicMac = WiFi.macAddress().substring(8);
  topicMac.replace(":", "");
  loadConfig();
  apConfig(topicMac);
  WiFi.disconnect();
  WiFi.mode(WIFI_STA);
  WiFi.begin(config.stassid, config.stapsw);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  topicMac = topicMac + aptype;
  getUid(topicMac, false);
  client.setServer(mqtt_server, mqtt_server_port);
  client.setCallback(callback);
  Serial.println("Config success");
  WOL.calculateBroadcastAddress(WiFi.localIP(), WiFi.subnetMask());  //wol
  Serial.printf("wake MAC:%s\n",config.MACAddress);

  if (! aht.begin()) {
    Serial.println("Could not find AHT10? Check wiring");
    while (1) delay(10);
  }
  Serial.println("AHT10 found");
}

void loop() {
  static unsigned long previousMillis = 0;
  static unsigned long currentMillis = 0;
  static sensors_event_t humidity, temp;
  static bool firstState = false;

  if (!client.connected())
    reconnect();
  client.loop();

  if(currentMillis-previousMillis == MyTimer){
    u8g2.firstPage();
    do {
        if(pcState)
          u8g2.drawStr(0, 12, "pc state: on ");
        else 
          u8g2.drawStr(0, 12, "pc state: off");
        u8g2.drawStr(0, 35, "Temp: ");u8g2.drawStr(118, 35, "C");u8g2.drawCircle(115, 24, 2);
        u8g2.drawStr(0, 55, "Humi: ");u8g2.drawStr(118, 55, "%");
        u8g2.setCursor(55, 35);u8g2.print(temp.temperature);
        u8g2.setCursor(55, 55);u8g2.print(humidity.relative_humidity);

    } while (u8g2.nextPage());
  }
  if(currentMillis-previousMillis > MyTimer*2 || firstState == false){
    static int t_count = 0;
    previousMillis = currentMillis;
    firstState = true;
    aht.getEvent(&humidity, &temp);
    t_count++;
    if(t_count > 50){
      t_count = 0;
      String msg = "#温度:" + (String)temp.temperature + "  #湿度:" + (String)humidity.relative_humidity;;
      client.publish(topicMac.c_str(), msg.c_str());
    }
  }  
  currentMillis = millis();
}
